phpseclib/Net/SFTP.php
- 1
<?php
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
- 33
- 34
- 35
- 36
- 37
- 38
- 39
- 40
- 41
- 42
- 43
- 44
- 45
- 46
- 47
- 48
- 49
- 50
- 51
- 52
- 53
- 54
- 55
- 56
- 57
- 58
- 59 if (!class_exists('Net_SSH2')) {
- 60 include_once 'SSH2.php';
- 61 }
- 62
- 63
- 64
- 65
- 66
- 67
- 68
- 69
- 70 define('NET_SFTP_LOG_SIMPLE', NET_SSH2_LOG_SIMPLE);
- 71
- 72
- 73
- 74 define('NET_SFTP_LOG_COMPLEX', NET_SSH2_LOG_COMPLEX);
- 75
- 76
- 77
- 78 define('NET_SFTP_LOG_REALTIME', 3);
- 79
- 80
- 81
- 82
- 83
- 84
- 85
- 86
- 87
- 88
- 89
- 90 define('NET_SFTP_CHANNEL', 0x100);
- 91
- 92
- 93
- 94
- 95
- 96
- 97
- 98
- 99 define('NET_SFTP_LOCAL_FILE', 1);
- 100
- 101
- 102
- 103
- 104 define('NET_SFTP_STRING', 2);
- 105
- 106
- 107
- 108
- 109 define('NET_SFTP_CALLBACK', 16);
- 110
- 111
- 112
- 113 define('NET_SFTP_RESUME', 4);
- 114
- 115
- 116
- 117 define('NET_SFTP_RESUME_START', 8);
- 118
- 119
- 120
- 121
- 122
- 123
- 124
- 125
- 126
- 127 class Net_SFTP extends Net_SSH2
- 128 {
- 129
- 130
- 131
- 132
- 133
- 134
- 135
- 136 var $packet_types = array();
- 137
- 138
- 139
- 140
- 141
- 142
- 143
- 144
- 145 var $status_codes = array();
- 146
- 147
- 148
- 149
- 150
- 151
- 152
- 153
- 154
- 155
- 156
- 157 var $request_id = false;
- 158
- 159
- 160
- 161
- 162
- 163
- 164
- 165
- 166
- 167
- 168
- 169 var $packet_type = -1;
- 170
- 171
- 172
- 173
- 174
- 175
- 176
- 177
- 178 var $packet_buffer = '';
- 179
- 180
- 181
- 182
- 183
- 184
- 185
- 186
- 187 var $extensions = array();
- 188
- 189
- 190
- 191
- 192
- 193
- 194
- 195
- 196 var $version;
- 197
- 198
- 199
- 200
- 201
- 202
- 203
- 204
- 205
- 206 var $pwd = false;
- 207
- 208
- 209
- 210
- 211
- 212
- 213
- 214
- 215 var $packet_type_log = array();
- 216
- 217
- 218
- 219
- 220
- 221
- 222
- 223
- 224 var $packet_log = array();
- 225
- 226
- 227
- 228
- 229
- 230
- 231
- 232
- 233
- 234 var $sftp_errors = array();
- 235
- 236
- 237
- 238
- 239
- 240
- 241
- 242
- 243
- 244
- 245
- 246
- 247
- 248 var $stat_cache = array();
- 249
- 250
- 251
- 252
- 253
- 254
- 255
- 256
- 257
- 258 var $max_sftp_packet;
- 259
- 260
- 261
- 262
- 263
- 264
- 265
- 266
- 267
- 268 var $use_stat_cache = true;
- 269
- 270
- 271
- 272
- 273
- 274
- 275
- 276
- 277
- 278 var $sortOptions = array();
- 279
- 280
- 281
- 282
- 283
- 284
- 285
- 286
- 287
- 288
- 289
- 290
- 291
- 292 var $canonicalize_paths = true;
- 293
- 294
- 295
- 296
- 297
- 298
- 299
- 300
- 301
- 302
- 303
- 304
- 305 function __construct($host, $port = 22, $timeout = 10)
- 306 {
- 307 parent::__construct($host, $port, $timeout);
- 308
- 309 $this->max_sftp_packet = 1 << 15;
- 310
- 311 $this->packet_types = array(
- 312 1 => 'NET_SFTP_INIT',
- 313 2 => 'NET_SFTP_VERSION',
- 314
- 315
- 316
- 317 3 => 'NET_SFTP_OPEN',
- 318 4 => 'NET_SFTP_CLOSE',
- 319 5 => 'NET_SFTP_READ',
- 320 6 => 'NET_SFTP_WRITE',
- 321 7 => 'NET_SFTP_LSTAT',
- 322 9 => 'NET_SFTP_SETSTAT',
- 323 11 => 'NET_SFTP_OPENDIR',
- 324 12 => 'NET_SFTP_READDIR',
- 325 13 => 'NET_SFTP_REMOVE',
- 326 14 => 'NET_SFTP_MKDIR',
- 327 15 => 'NET_SFTP_RMDIR',
- 328 16 => 'NET_SFTP_REALPATH',
- 329 17 => 'NET_SFTP_STAT',
- 330
- 331
- 332
- 333 18 => 'NET_SFTP_RENAME',
- 334 19 => 'NET_SFTP_READLINK',
- 335 20 => 'NET_SFTP_SYMLINK',
- 336
- 337 101=> 'NET_SFTP_STATUS',
- 338 102=> 'NET_SFTP_HANDLE',
- 339
- 340
- 341
- 342 103=> 'NET_SFTP_DATA',
- 343 104=> 'NET_SFTP_NAME',
- 344 105=> 'NET_SFTP_ATTRS',
- 345
- 346 200=> 'NET_SFTP_EXTENDED'
- 347 );
- 348 $this->status_codes = array(
- 349 0 => 'NET_SFTP_STATUS_OK',
- 350 1 => 'NET_SFTP_STATUS_EOF',
- 351 2 => 'NET_SFTP_STATUS_NO_SUCH_FILE',
- 352 3 => 'NET_SFTP_STATUS_PERMISSION_DENIED',
- 353 4 => 'NET_SFTP_STATUS_FAILURE',
- 354 5 => 'NET_SFTP_STATUS_BAD_MESSAGE',
- 355 6 => 'NET_SFTP_STATUS_NO_CONNECTION',
- 356 7 => 'NET_SFTP_STATUS_CONNECTION_LOST',
- 357 8 => 'NET_SFTP_STATUS_OP_UNSUPPORTED',
- 358 9 => 'NET_SFTP_STATUS_INVALID_HANDLE',
- 359 10 => 'NET_SFTP_STATUS_NO_SUCH_PATH',
- 360 11 => 'NET_SFTP_STATUS_FILE_ALREADY_EXISTS',
- 361 12 => 'NET_SFTP_STATUS_WRITE_PROTECT',
- 362 13 => 'NET_SFTP_STATUS_NO_MEDIA',
- 363 14 => 'NET_SFTP_STATUS_NO_SPACE_ON_FILESYSTEM',
- 364 15 => 'NET_SFTP_STATUS_QUOTA_EXCEEDED',
- 365 16 => 'NET_SFTP_STATUS_UNKNOWN_PRINCIPAL',
- 366 17 => 'NET_SFTP_STATUS_LOCK_CONFLICT',
- 367 18 => 'NET_SFTP_STATUS_DIR_NOT_EMPTY',
- 368 19 => 'NET_SFTP_STATUS_NOT_A_DIRECTORY',
- 369 20 => 'NET_SFTP_STATUS_INVALID_FILENAME',
- 370 21 => 'NET_SFTP_STATUS_LINK_LOOP',
- 371 22 => 'NET_SFTP_STATUS_CANNOT_DELETE',
- 372 23 => 'NET_SFTP_STATUS_INVALID_PARAMETER',
- 373 24 => 'NET_SFTP_STATUS_FILE_IS_A_DIRECTORY',
- 374 25 => 'NET_SFTP_STATUS_BYTE_RANGE_LOCK_CONFLICT',
- 375 26 => 'NET_SFTP_STATUS_BYTE_RANGE_LOCK_REFUSED',
- 376 27 => 'NET_SFTP_STATUS_DELETE_PENDING',
- 377 28 => 'NET_SFTP_STATUS_FILE_CORRUPT',
- 378 29 => 'NET_SFTP_STATUS_OWNER_INVALID',
- 379 30 => 'NET_SFTP_STATUS_GROUP_INVALID',
- 380 31 => 'NET_SFTP_STATUS_NO_MATCHING_BYTE_RANGE_LOCK'
- 381 );
- 382
- 383
- 384 $this->attributes = array(
- 385 0x00000001 => 'NET_SFTP_ATTR_SIZE',
- 386 0x00000002 => 'NET_SFTP_ATTR_UIDGID',
- 387 0x00000004 => 'NET_SFTP_ATTR_PERMISSIONS',
- 388 0x00000008 => 'NET_SFTP_ATTR_ACCESSTIME',
- 389
- 390
- 391
- 392
- 393 (-1 << 31) & 0xFFFFFFFF => 'NET_SFTP_ATTR_EXTENDED'
- 394 );
- 395
- 396
- 397
- 398 $this->open_flags = array(
- 399 0x00000001 => 'NET_SFTP_OPEN_READ',
- 400 0x00000002 => 'NET_SFTP_OPEN_WRITE',
- 401 0x00000004 => 'NET_SFTP_OPEN_APPEND',
- 402 0x00000008 => 'NET_SFTP_OPEN_CREATE',
- 403 0x00000010 => 'NET_SFTP_OPEN_TRUNCATE',
- 404 0x00000020 => 'NET_SFTP_OPEN_EXCL'
- 405 );
- 406
- 407
- 408 $this->file_types = array(
- 409 1 => 'NET_SFTP_TYPE_REGULAR',
- 410 2 => 'NET_SFTP_TYPE_DIRECTORY',
- 411 3 => 'NET_SFTP_TYPE_SYMLINK',
- 412 4 => 'NET_SFTP_TYPE_SPECIAL',
- 413 5 => 'NET_SFTP_TYPE_UNKNOWN',
- 414
- 415
- 416 6 => 'NET_SFTP_TYPE_SOCKET',
- 417 7 => 'NET_SFTP_TYPE_CHAR_DEVICE',
- 418 8 => 'NET_SFTP_TYPE_BLOCK_DEVICE',
- 419 9 => 'NET_SFTP_TYPE_FIFO'
- 420 );
- 421 $this->_define_array(
- 422 $this->packet_types,
- 423 $this->status_codes,
- 424 $this->attributes,
- 425 $this->open_flags,
- 426 $this->file_types
- 427 );
- 428
- 429 if (!defined('NET_SFTP_QUEUE_SIZE')) {
- 430 define('NET_SFTP_QUEUE_SIZE', 32);
- 431 }
- 432 }
- 433
- 434
- 435
- 436
- 437
- 438
- 439
- 440
- 441
- 442
- 443 function Net_SFTP($host, $port = 22, $timeout = 10)
- 444 {
- 445 $this->__construct($host, $port, $timeout);
- 446 }
- 447
- 448
- 449
- 450
- 451
- 452
- 453
- 454
- 455
- 456 function login($username)
- 457 {
- 458 $args = func_get_args();
- 459 if (!call_user_func_array(array(&$this, '_login'), $args)) {
- 460 return false;
- 461 }
- 462
- 463 $this->window_size_server_to_client[NET_SFTP_CHANNEL] = $this->window_size;
- 464
- 465 $packet = pack(
- 466 'CNa*N3',
- 467 NET_SSH2_MSG_CHANNEL_OPEN,
- 468 strlen('session'),
- 469 'session',
- 470 NET_SFTP_CHANNEL,
- 471 $this->window_size,
- 472 0x4000
- 473 );
- 474
- 475 if (!$this->_send_binary_packet($packet)) {
- 476 return false;
- 477 }
- 478
- 479 $this->channel_status[NET_SFTP_CHANNEL] = NET_SSH2_MSG_CHANNEL_OPEN;
- 480
- 481 $response = $this->_get_channel_packet(NET_SFTP_CHANNEL, true);
- 482 if ($response === false) {
- 483 return false;
- 484 }
- 485
- 486 $packet = pack(
- 487 'CNNa*CNa*',
- 488 NET_SSH2_MSG_CHANNEL_REQUEST,
- 489 $this->server_channels[NET_SFTP_CHANNEL],
- 490 strlen('subsystem'),
- 491 'subsystem',
- 492 1,
- 493 strlen('sftp'),
- 494 'sftp'
- 495 );
- 496 if (!$this->_send_binary_packet($packet)) {
- 497 return false;
- 498 }
- 499
- 500 $this->channel_status[NET_SFTP_CHANNEL] = NET_SSH2_MSG_CHANNEL_REQUEST;
- 501
- 502 $response = $this->_get_channel_packet(NET_SFTP_CHANNEL, true);
- 503 if ($response === false) {
- 504
- 505 $command = "test -x /usr/lib/sftp-server && exec /usr/lib/sftp-server\n" .
- 506 "test -x /usr/local/lib/sftp-server && exec /usr/local/lib/sftp-server\n" .
- 507 "exec sftp-server";
- 508
- 509
- 510 $packet = pack(
- 511 'CNNa*CNa*',
- 512 NET_SSH2_MSG_CHANNEL_REQUEST,
- 513 $this->server_channels[NET_SFTP_CHANNEL],
- 514 strlen('exec'),
- 515 'exec',
- 516 1,
- 517 strlen($command),
- 518 $command
- 519 );
- 520 if (!$this->_send_binary_packet($packet)) {
- 521 return false;
- 522 }
- 523
- 524 $this->channel_status[NET_SFTP_CHANNEL] = NET_SSH2_MSG_CHANNEL_REQUEST;
- 525
- 526 $response = $this->_get_channel_packet(NET_SFTP_CHANNEL, true);
- 527 if ($response === false) {
- 528 return false;
- 529 }
- 530 }
- 531
- 532 $this->channel_status[NET_SFTP_CHANNEL] = NET_SSH2_MSG_CHANNEL_DATA;
- 533
- 534 if (!$this->_send_sftp_packet(NET_SFTP_INIT, "\0\0\0\3")) {
- 535 return false;
- 536 }
- 537
- 538 $response = $this->_get_sftp_packet();
- 539 if ($this->packet_type != NET_SFTP_VERSION) {
- 540 user_error('Expected SSH_FXP_VERSION');
- 541 return false;
- 542 }
- 543
- 544 if (strlen($response) < 4) {
- 545 return false;
- 546 }
- 547 extract(unpack('Nversion', $this->_string_shift($response, 4)));
- 548 $this->version = $version;
- 549 while (!empty($response)) {
- 550 if (strlen($response) < 4) {
- 551 return false;
- 552 }
- 553 extract(unpack('Nlength', $this->_string_shift($response, 4)));
- 554 $key = $this->_string_shift($response, $length);
- 555 if (strlen($response) < 4) {
- 556 return false;
- 557 }
- 558 extract(unpack('Nlength', $this->_string_shift($response, 4)));
- 559 $value = $this->_string_shift($response, $length);
- 560 $this->extensions[$key] = $value;
- 561 }
- 562
- 563
- 564
- 565
- 566
- 567
- 568
- 569
- 570
- 571
- 572
- 573
- 574
- 575
- 576
- 577 $this->request_id = 1;
- 578
- 579
- 580
- 581
- 582
- 583
- 584
- 585
- 586
- 587
- 588
- 589
- 590
- 591
- 592
- 593
- 594
- 595
- 596
- 597
- 598
- 599
- 600
- 601
- 602 switch ($this->version) {
- 603 case 2:
- 604 case 3:
- 605 break;
- 606 default:
- 607 return false;
- 608 }
- 609
- 610 $this->pwd = $this->_realpath('.');
- 611
- 612 $this->_update_stat_cache($this->pwd, array());
- 613
- 614 return true;
- 615 }
- 616
- 617
- 618
- 619
- 620
- 621
- 622 function disableStatCache()
- 623 {
- 624 $this->use_stat_cache = false;
- 625 }
- 626
- 627
- 628
- 629
- 630
- 631
- 632 function enableStatCache()
- 633 {
- 634 $this->use_stat_cache = true;
- 635 }
- 636
- 637
- 638
- 639
- 640
- 641
- 642 function clearStatCache()
- 643 {
- 644 $this->stat_cache = array();
- 645 }
- 646
- 647
- 648
- 649
- 650
- 651
- 652 function enablePathCanonicalization()
- 653 {
- 654 $this->canonicalize_paths = true;
- 655 }
- 656
- 657
- 658
- 659
- 660
- 661
- 662 function disablePathCanonicalization()
- 663 {
- 664 $this->canonicalize_paths = false;
- 665 }
- 666
- 667
- 668
- 669
- 670
- 671
- 672
- 673 function pwd()
- 674 {
- 675 return $this->pwd;
- 676 }
- 677
- 678
- 679
- 680
- 681
- 682
- 683
- 684
- 685 function _logError($response, $status = -1)
- 686 {
- 687 if ($status == -1) {
- 688 if (strlen($response) < 4) {
- 689 return;
- 690 }
- 691 extract(unpack('Nstatus', $this->_string_shift($response, 4)));
- 692 }
- 693
- 694 $error = $this->status_codes[$status];
- 695
- 696 if ($this->version > 2 || strlen($response) < 4) {
- 697 extract(unpack('Nlength', $this->_string_shift($response, 4)));
- 698 $this->sftp_errors[] = $error . ': ' . $this->_string_shift($response, $length);
- 699 } else {
- 700 $this->sftp_errors[] = $error;
- 701 }
- 702 }
- 703
- 704
- 705
- 706
- 707
- 708
- 709
- 710
- 711
- 712
- 713
- 714 function realpath($path)
- 715 {
- 716 return $this->_realpath($path);
- 717 }
- 718
- 719
- 720
- 721
- 722
- 723
- 724
- 725
- 726
- 727
- 728
- 729
- 730
- 731
- 732
- 733 function _realpath($path)
- 734 {
- 735 if (!$this->canonicalize_paths) {
- 736 return $path;
- 737 }
- 738
- 739 if ($this->pwd === false) {
- 740
- 741 if (!$this->_send_sftp_packet(NET_SFTP_REALPATH, pack('Na*', strlen($path), $path))) {
- 742 return false;
- 743 }
- 744
- 745 $response = $this->_get_sftp_packet();
- 746 switch ($this->packet_type) {
- 747 case NET_SFTP_NAME:
- 748
- 749
- 750
- 751 $this->_string_shift($response, 4);
- 752 if (strlen($response) < 4) {
- 753 return false;
- 754 }
- 755 extract(unpack('Nlength', $this->_string_shift($response, 4)));
- 756 return $this->_string_shift($response, $length);
- 757 case NET_SFTP_STATUS:
- 758 $this->_logError($response);
- 759 return false;
- 760 default:
- 761 user_error('Expected SSH_FXP_NAME or SSH_FXP_STATUS');
- 762 return false;
- 763 }
- 764 }
- 765
- 766 if ($path[0] != '/') {
- 767 $path = $this->pwd . '/' . $path;
- 768 }
- 769
- 770 $path = explode('/', $path);
- 771 $new = array();
- 772 foreach ($path as $dir) {
- 773 if (!strlen($dir)) {
- 774 continue;
- 775 }
- 776 switch ($dir) {
- 777 case '..':
- 778 array_pop($new);
- 779 case '.':
- 780 break;
- 781 default:
- 782 $new[] = $dir;
- 783 }
- 784 }
- 785
- 786 return '/' . implode('/', $new);
- 787 }
- 788
- 789
- 790
- 791
- 792
- 793
- 794
- 795
- 796 function chdir($dir)
- 797 {
- 798 if (!($this->bitmap & NET_SSH2_MASK_LOGIN)) {
- 799 return false;
- 800 }
- 801
- 802
- 803 if ($dir === '') {
- 804 $dir = './';
- 805
- 806 } elseif ($dir[strlen($dir) - 1] != '/') {
- 807 $dir.= '/';
- 808 }
- 809
- 810 $dir = $this->_realpath($dir);
- 811
- 812
- 813 if ($this->use_stat_cache && is_array($this->_query_stat_cache($dir))) {
- 814 $this->pwd = $dir;
- 815 return true;
- 816 }
- 817
- 818
- 819
- 820
- 821
- 822
- 823 if (!$this->_send_sftp_packet(NET_SFTP_OPENDIR, pack('Na*', strlen($dir), $dir))) {
- 824 return false;
- 825 }
- 826
- 827
- 828 $response = $this->_get_sftp_packet();
- 829 switch ($this->packet_type) {
- 830 case NET_SFTP_HANDLE:
- 831 $handle = substr($response, 4);
- 832 break;
- 833 case NET_SFTP_STATUS:
- 834 $this->_logError($response);
- 835 return false;
- 836 default:
- 837 user_error('Expected SSH_FXP_HANDLE or SSH_FXP_STATUS');
- 838 return false;
- 839 }
- 840
- 841 if (!$this->_close_handle($handle)) {
- 842 return false;
- 843 }
- 844
- 845 $this->_update_stat_cache($dir, array());
- 846
- 847 $this->pwd = $dir;
- 848 return true;
- 849 }
- 850
- 851
- 852
- 853
- 854
- 855
- 856
- 857
- 858
- 859 function nlist($dir = '.', $recursive = false)
- 860 {
- 861 return $this->_nlist_helper($dir, $recursive, '');
- 862 }
- 863
- 864
- 865
- 866
- 867
- 868
- 869
- 870
- 871
- 872
- 873 function _nlist_helper($dir, $recursive, $relativeDir)
- 874 {
- 875 $files = $this->_list($dir, false);
- 876
- 877 if (!$recursive || $files === false) {
- 878 return $files;
- 879 }
- 880
- 881 $result = array();
- 882 foreach ($files as $value) {
- 883 if ($value == '.' || $value == '..') {
- 884 if ($relativeDir == '') {
- 885 $result[] = $value;
- 886 }
- 887 continue;
- 888 }
- 889 if (is_array($this->_query_stat_cache($this->_realpath($dir . '/' . $value)))) {
- 890 $temp = $this->_nlist_helper($dir . '/' . $value, true, $relativeDir . $value . '/');
- 891 $result = array_merge($result, $temp);
- 892 } else {
- 893 $result[] = $relativeDir . $value;
- 894 }
- 895 }
- 896
- 897 return $result;
- 898 }
- 899
- 900
- 901
- 902
- 903
- 904
- 905
- 906
- 907
- 908 function rawlist($dir = '.', $recursive = false)
- 909 {
- 910 $files = $this->_list($dir, true);
- 911 if (!$recursive || $files === false) {
- 912 return $files;
- 913 }
- 914
- 915 static $depth = 0;
- 916
- 917 foreach ($files as $key => $value) {
- 918 if ($depth != 0 && $key == '..') {
- 919 unset($files[$key]);
- 920 continue;
- 921 }
- 922 if ($key != '.' && $key != '..' && is_array($this->_query_stat_cache($this->_realpath($dir . '/' . $key)))) {
- 923 $depth++;
- 924 $files[$key] = $this->rawlist($dir . '/' . $key, true);
- 925 $depth--;
- 926 } else {
- 927 $files[$key] = (object) $value;
- 928 }
- 929 }
- 930
- 931 return $files;
- 932 }
- 933
- 934
- 935
- 936
- 937
- 938
- 939
- 940
- 941
- 942 function _list($dir, $raw = true)
- 943 {
- 944 if (!($this->bitmap & NET_SSH2_MASK_LOGIN)) {
- 945 return false;
- 946 }
- 947
- 948 $dir = $this->_realpath($dir . '/');
- 949 if ($dir === false) {
- 950 return false;
- 951 }
- 952
- 953
- 954 if (!$this->_send_sftp_packet(NET_SFTP_OPENDIR, pack('Na*', strlen($dir), $dir))) {
- 955 return false;
- 956 }
- 957
- 958 $response = $this->_get_sftp_packet();
- 959 switch ($this->packet_type) {
- 960 case NET_SFTP_HANDLE:
- 961
- 962
- 963
- 964 $handle = substr($response, 4);
- 965 break;
- 966 case NET_SFTP_STATUS:
- 967
- 968 $this->_logError($response);
- 969 return false;
- 970 default:
- 971 user_error('Expected SSH_FXP_HANDLE or SSH_FXP_STATUS');
- 972 return false;
- 973 }
- 974
- 975 $this->_update_stat_cache($dir, array());
- 976
- 977 $contents = array();
- 978 while (true) {
- 979
- 980
- 981
- 982 if (!$this->_send_sftp_packet(NET_SFTP_READDIR, pack('Na*', strlen($handle), $handle))) {
- 983 return false;
- 984 }
- 985
- 986 $response = $this->_get_sftp_packet();
- 987 switch ($this->packet_type) {
- 988 case NET_SFTP_NAME:
- 989 if (strlen($response) < 4) {
- 990 return false;
- 991 }
- 992 extract(unpack('Ncount', $this->_string_shift($response, 4)));
- 993 for ($i = 0; $i < $count; $i++) {
- 994 if (strlen($response) < 4) {
- 995 return false;
- 996 }
- 997 extract(unpack('Nlength', $this->_string_shift($response, 4)));
- 998 $shortname = $this->_string_shift($response, $length);
- 999 if (strlen($response) < 4) {
- 1000 return false;
- 1001 }
- 1002 extract(unpack('Nlength', $this->_string_shift($response, 4)));
- 1003 $longname = $this->_string_shift($response, $length);
- 1004 $attributes = $this->_parseAttributes($response);
- 1005 if (!isset($attributes['type'])) {
- 1006 $fileType = $this->_parseLongname($longname);
- 1007 if ($fileType) {
- 1008 $attributes['type'] = $fileType;
- 1009 }
- 1010 }
- 1011 $contents[$shortname] = $attributes + array('filename' => $shortname);
- 1012
- 1013 if (isset($attributes['type']) && $attributes['type'] == NET_SFTP_TYPE_DIRECTORY && ($shortname != '.' && $shortname != '..')) {
- 1014 $this->_update_stat_cache($dir . '/' . $shortname, array());
- 1015 } else {
- 1016 if ($shortname == '..') {
- 1017 $temp = $this->_realpath($dir . '/..') . '/.';
- 1018 } else {
- 1019 $temp = $dir . '/' . $shortname;
- 1020 }
- 1021 $this->_update_stat_cache($temp, (object) array('lstat' => $attributes));
- 1022 }
- 1023
- 1024
- 1025 }
- 1026 break;
- 1027 case NET_SFTP_STATUS:
- 1028 if (strlen($response) < 4) {
- 1029 return false;
- 1030 }
- 1031 extract(unpack('Nstatus', $this->_string_shift($response, 4)));
- 1032 if ($status != NET_SFTP_STATUS_EOF) {
- 1033 $this->_logError($response, $status);
- 1034 return false;
- 1035 }
- 1036 break 2;
- 1037 default:
- 1038 user_error('Expected SSH_FXP_NAME or SSH_FXP_STATUS');
- 1039 return false;
- 1040 }
- 1041 }
- 1042
- 1043 if (!$this->_close_handle($handle)) {
- 1044 return false;
- 1045 }
- 1046
- 1047 if (count($this->sortOptions)) {
- 1048 uasort($contents, array(&$this, '_comparator'));
- 1049 }
- 1050
- 1051 return $raw ? $contents : array_keys($contents);
- 1052 }
- 1053
- 1054
- 1055
- 1056
- 1057
- 1058
- 1059
- 1060
- 1061
- 1062
- 1063
- 1064 function _comparator($a, $b)
- 1065 {
- 1066 switch (true) {
- 1067 case $a['filename'] === '.' || $b['filename'] === '.':
- 1068 if ($a['filename'] === $b['filename']) {
- 1069 return 0;
- 1070 }
- 1071 return $a['filename'] === '.' ? -1 : 1;
- 1072 case $a['filename'] === '..' || $b['filename'] === '..':
- 1073 if ($a['filename'] === $b['filename']) {
- 1074 return 0;
- 1075 }
- 1076 return $a['filename'] === '..' ? -1 : 1;
- 1077 case isset($a['type']) && $a['type'] === NET_SFTP_TYPE_DIRECTORY:
- 1078 if (!isset($b['type'])) {
- 1079 return 1;
- 1080 }
- 1081 if ($b['type'] !== $a['type']) {
- 1082 return -1;
- 1083 }
- 1084 break;
- 1085 case isset($b['type']) && $b['type'] === NET_SFTP_TYPE_DIRECTORY:
- 1086 return 1;
- 1087 }
- 1088 foreach ($this->sortOptions as $sort => $order) {
- 1089 if (!isset($a[$sort]) || !isset($b[$sort])) {
- 1090 if (isset($a[$sort])) {
- 1091 return -1;
- 1092 }
- 1093 if (isset($b[$sort])) {
- 1094 return 1;
- 1095 }
- 1096 return 0;
- 1097 }
- 1098 switch ($sort) {
- 1099 case 'filename':
- 1100 $result = strcasecmp($a['filename'], $b['filename']);
- 1101 if ($result) {
- 1102 return $order === SORT_DESC ? -$result : $result;
- 1103 }
- 1104 break;
- 1105 case 'permissions':
- 1106 case 'mode':
- 1107 $a[$sort]&= 07777;
- 1108 $b[$sort]&= 07777;
- 1109 default:
- 1110 if ($a[$sort] === $b[$sort]) {
- 1111 break;
- 1112 }
- 1113 return $order === SORT_ASC ? $a[$sort] - $b[$sort] : $b[$sort] - $a[$sort];
- 1114 }
- 1115 }
- 1116 }
- 1117
- 1118
- 1119
- 1120
- 1121
- 1122
- 1123
- 1124
- 1125
- 1126
- 1127
- 1128
- 1129
- 1130
- 1131
- 1132
- 1133
- 1134
- 1135
- 1136
- 1137
- 1138 function setListOrder()
- 1139 {
- 1140 $this->sortOptions = array();
- 1141 $args = func_get_args();
- 1142 if (empty($args)) {
- 1143 return;
- 1144 }
- 1145 $len = count($args) & 0x7FFFFFFE;
- 1146 for ($i = 0; $i < $len; $i+=2) {
- 1147 $this->sortOptions[$args[$i]] = $args[$i + 1];
- 1148 }
- 1149 if (!count($this->sortOptions)) {
- 1150 $this->sortOptions = array('bogus' => true);
- 1151 }
- 1152 }
- 1153
- 1154
- 1155
- 1156
- 1157
- 1158
- 1159
- 1160
- 1161
- 1162
- 1163 function size($filename)
- 1164 {
- 1165 if (!($this->bitmap & NET_SSH2_MASK_LOGIN)) {
- 1166 return false;
- 1167 }
- 1168
- 1169 $result = $this->stat($filename);
- 1170 if ($result === false) {
- 1171 return false;
- 1172 }
- 1173 return isset($result['size']) ? $result['size'] : -1;
- 1174 }
- 1175
- 1176
- 1177
- 1178
- 1179
- 1180
- 1181
- 1182
- 1183 function _update_stat_cache($path, $value)
- 1184 {
- 1185 if ($this->use_stat_cache === false) {
- 1186 return;
- 1187 }
- 1188
- 1189
- 1190 $dirs = explode('/', preg_replace('#^/|/(?=/)|/$#', '', $path));
- 1191
- 1192 $temp = &$this->stat_cache;
- 1193 $max = count($dirs) - 1;
- 1194 foreach ($dirs as $i => $dir) {
- 1195
- 1196
- 1197
- 1198 if (is_object($temp)) {
- 1199 $temp = array();
- 1200 }
- 1201 if (!isset($temp[$dir])) {
- 1202 $temp[$dir] = array();
- 1203 }
- 1204 if ($i === $max) {
- 1205 if (is_object($temp[$dir]) && is_object($value)) {
- 1206 if (!isset($value->stat) && isset($temp[$dir]->stat)) {
- 1207 $value->stat = $temp[$dir]->stat;
- 1208 }
- 1209 if (!isset($value->lstat) && isset($temp[$dir]->lstat)) {
- 1210 $value->lstat = $temp[$dir]->lstat;
- 1211 }
- 1212 }
- 1213 $temp[$dir] = $value;
- 1214 break;
- 1215 }
- 1216 $temp = &$temp[$dir];
- 1217 }
- 1218 }
- 1219
- 1220
- 1221
- 1222
- 1223
- 1224
- 1225
- 1226
- 1227 function _remove_from_stat_cache($path)
- 1228 {
- 1229 $dirs = explode('/', preg_replace('#^/|/(?=/)|/$#', '', $path));
- 1230
- 1231 $temp = &$this->stat_cache;
- 1232 $max = count($dirs) - 1;
- 1233 foreach ($dirs as $i => $dir) {
- 1234 if ($i === $max) {
- 1235 unset($temp[$dir]);
- 1236 return true;
- 1237 }
- 1238 if (!isset($temp[$dir])) {
- 1239 return false;
- 1240 }
- 1241 $temp = &$temp[$dir];
- 1242 }
- 1243 }
- 1244
- 1245
- 1246
- 1247
- 1248
- 1249
- 1250
- 1251
- 1252
- 1253
- 1254 function _query_stat_cache($path)
- 1255 {
- 1256 $dirs = explode('/', preg_replace('#^/|/(?=/)|/$#', '', $path));
- 1257
- 1258 $temp = &$this->stat_cache;
- 1259 foreach ($dirs as $dir) {
- 1260 if (!isset($temp[$dir])) {
- 1261 return null;
- 1262 }
- 1263 $temp = &$temp[$dir];
- 1264 }
- 1265 return $temp;
- 1266 }
- 1267
- 1268
- 1269
- 1270
- 1271
- 1272
- 1273
- 1274
- 1275
- 1276
- 1277 function stat($filename)
- 1278 {
- 1279 if (!($this->bitmap & NET_SSH2_MASK_LOGIN)) {
- 1280 return false;
- 1281 }
- 1282
- 1283 $filename = $this->_realpath($filename);
- 1284 if ($filename === false) {
- 1285 return false;
- 1286 }
- 1287
- 1288 if ($this->use_stat_cache) {
- 1289 $result = $this->_query_stat_cache($filename);
- 1290 if (is_array($result) && isset($result['.']) && isset($result['.']->stat)) {
- 1291 return $result['.']->stat;
- 1292 }
- 1293 if (is_object($result) && isset($result->stat)) {
- 1294 return $result->stat;
- 1295 }
- 1296 }
- 1297
- 1298 $stat = $this->_stat($filename, NET_SFTP_STAT);
- 1299 if ($stat === false) {
- 1300 $this->_remove_from_stat_cache($filename);
- 1301 return false;
- 1302 }
- 1303 if (isset($stat['type'])) {
- 1304 if ($stat['type'] == NET_SFTP_TYPE_DIRECTORY) {
- 1305 $filename.= '/.';
- 1306 }
- 1307 $this->_update_stat_cache($filename, (object) array('stat' => $stat));
- 1308 return $stat;
- 1309 }
- 1310
- 1311 $pwd = $this->pwd;
- 1312 $stat['type'] = $this->chdir($filename) ?
- 1313 NET_SFTP_TYPE_DIRECTORY :
- 1314 NET_SFTP_TYPE_REGULAR;
- 1315 $this->pwd = $pwd;
- 1316
- 1317 if ($stat['type'] == NET_SFTP_TYPE_DIRECTORY) {
- 1318 $filename.= '/.';
- 1319 }
- 1320 $this->_update_stat_cache($filename, (object) array('stat' => $stat));
- 1321
- 1322 return $stat;
- 1323 }
- 1324
- 1325
- 1326
- 1327
- 1328
- 1329
- 1330
- 1331
- 1332
- 1333
- 1334 function lstat($filename)
- 1335 {
- 1336 if (!($this->bitmap & NET_SSH2_MASK_LOGIN)) {
- 1337 return false;
- 1338 }
- 1339
- 1340 $filename = $this->_realpath($filename);
- 1341 if ($filename === false) {
- 1342 return false;
- 1343 }
- 1344
- 1345 if ($this->use_stat_cache) {
- 1346 $result = $this->_query_stat_cache($filename);
- 1347 if (is_array($result) && isset($result['.']) && isset($result['.']->lstat)) {
- 1348 return $result['.']->lstat;
- 1349 }
- 1350 if (is_object($result) && isset($result->lstat)) {
- 1351 return $result->lstat;
- 1352 }
- 1353 }
- 1354
- 1355 $lstat = $this->_stat($filename, NET_SFTP_LSTAT);
- 1356 if ($lstat === false) {
- 1357 $this->_remove_from_stat_cache($filename);
- 1358 return false;
- 1359 }
- 1360 if (isset($lstat['type'])) {
- 1361 if ($lstat['type'] == NET_SFTP_TYPE_DIRECTORY) {
- 1362 $filename.= '/.';
- 1363 }
- 1364 $this->_update_stat_cache($filename, (object) array('lstat' => $lstat));
- 1365 return $lstat;
- 1366 }
- 1367
- 1368 $stat = $this->_stat($filename, NET_SFTP_STAT);
- 1369
- 1370 if ($lstat != $stat) {
- 1371 $lstat = array_merge($lstat, array('type' => NET_SFTP_TYPE_SYMLINK));
- 1372 $this->_update_stat_cache($filename, (object) array('lstat' => $lstat));
- 1373 return $stat;
- 1374 }
- 1375
- 1376 $pwd = $this->pwd;
- 1377 $lstat['type'] = $this->chdir($filename) ?
- 1378 NET_SFTP_TYPE_DIRECTORY :
- 1379 NET_SFTP_TYPE_REGULAR;
- 1380 $this->pwd = $pwd;
- 1381
- 1382 if ($lstat['type'] == NET_SFTP_TYPE_DIRECTORY) {
- 1383 $filename.= '/.';
- 1384 }
- 1385 $this->_update_stat_cache($filename, (object) array('lstat' => $lstat));
- 1386
- 1387 return $lstat;
- 1388 }
- 1389
- 1390
- 1391
- 1392
- 1393
- 1394
- 1395
- 1396
- 1397
- 1398
- 1399
- 1400
- 1401 function _stat($filename, $type)
- 1402 {
- 1403
- 1404 $packet = pack('Na*', strlen($filename), $filename);
- 1405 if (!$this->_send_sftp_packet($type, $packet)) {
- 1406 return false;
- 1407 }
- 1408
- 1409 $response = $this->_get_sftp_packet();
- 1410 switch ($this->packet_type) {
- 1411 case NET_SFTP_ATTRS:
- 1412 return $this->_parseAttributes($response);
- 1413 case NET_SFTP_STATUS:
- 1414 $this->_logError($response);
- 1415 return false;
- 1416 }
- 1417
- 1418 user_error('Expected SSH_FXP_ATTRS or SSH_FXP_STATUS');
- 1419 return false;
- 1420 }
- 1421
- 1422
- 1423
- 1424
- 1425
- 1426
- 1427
- 1428
- 1429
- 1430 function truncate($filename, $new_size)
- 1431 {
- 1432 $attr = pack('N3', NET_SFTP_ATTR_SIZE, $new_size / 4294967296, $new_size);
- 1433
- 1434 return $this->_setstat($filename, $attr, false);
- 1435 }
- 1436
- 1437
- 1438
- 1439
- 1440
- 1441
- 1442
- 1443
- 1444
- 1445
- 1446
- 1447
- 1448 function touch($filename, $time = null, $atime = null)
- 1449 {
- 1450 if (!($this->bitmap & NET_SSH2_MASK_LOGIN)) {
- 1451 return false;
- 1452 }
- 1453
- 1454 $filename = $this->_realpath($filename);
- 1455 if ($filename === false) {
- 1456 return false;
- 1457 }
- 1458
- 1459 if (!isset($time)) {
- 1460 $time = time();
- 1461 }
- 1462 if (!isset($atime)) {
- 1463 $atime = $time;
- 1464 }
- 1465
- 1466 $flags = NET_SFTP_OPEN_WRITE | NET_SFTP_OPEN_CREATE | NET_SFTP_OPEN_EXCL;
- 1467 $attr = pack('N3', NET_SFTP_ATTR_ACCESSTIME, $time, $atime);
- 1468 $packet = pack('Na*Na*', strlen($filename), $filename, $flags, $attr);
- 1469 if (!$this->_send_sftp_packet(NET_SFTP_OPEN, $packet)) {
- 1470 return false;
- 1471 }
- 1472
- 1473 $response = $this->_get_sftp_packet();
- 1474 switch ($this->packet_type) {
- 1475 case NET_SFTP_HANDLE:
- 1476 return $this->_close_handle(substr($response, 4));
- 1477 case NET_SFTP_STATUS:
- 1478 $this->_logError($response);
- 1479 break;
- 1480 default:
- 1481 user_error('Expected SSH_FXP_HANDLE or SSH_FXP_STATUS');
- 1482 return false;
- 1483 }
- 1484
- 1485 return $this->_setstat($filename, $attr, false);
- 1486 }
- 1487
- 1488
- 1489
- 1490
- 1491
- 1492
- 1493
- 1494
- 1495
- 1496
- 1497
- 1498
- 1499 function chown($filename, $uid, $recursive = false)
- 1500 {
- 1501
- 1502
- 1503 $attr = pack('N3', NET_SFTP_ATTR_UIDGID, $uid, -1);
- 1504
- 1505 return $this->_setstat($filename, $attr, $recursive);
- 1506 }
- 1507
- 1508
- 1509
- 1510
- 1511
- 1512
- 1513
- 1514
- 1515
- 1516
- 1517
- 1518
- 1519 function chgrp($filename, $gid, $recursive = false)
- 1520 {
- 1521 $attr = pack('N3', NET_SFTP_ATTR_UIDGID, -1, $gid);
- 1522
- 1523 return $this->_setstat($filename, $attr, $recursive);
- 1524 }
- 1525
- 1526
- 1527
- 1528
- 1529
- 1530
- 1531
- 1532
- 1533
- 1534
- 1535
- 1536
- 1537
- 1538 function chmod($mode, $filename, $recursive = false)
- 1539 {
- 1540 if (is_string($mode) && is_int($filename)) {
- 1541 $temp = $mode;
- 1542 $mode = $filename;
- 1543 $filename = $temp;
- 1544 }
- 1545
- 1546 $attr = pack('N2', NET_SFTP_ATTR_PERMISSIONS, $mode & 07777);
- 1547 if (!$this->_setstat($filename, $attr, $recursive)) {
- 1548 return false;
- 1549 }
- 1550 if ($recursive) {
- 1551 return true;
- 1552 }
- 1553
- 1554 $filename = $this->realpath($filename);
- 1555
- 1556
- 1557
- 1558 $packet = pack('Na*', strlen($filename), $filename);
- 1559 if (!$this->_send_sftp_packet(NET_SFTP_STAT, $packet)) {
- 1560 return false;
- 1561 }
- 1562
- 1563 $response = $this->_get_sftp_packet();
- 1564 switch ($this->packet_type) {
- 1565 case NET_SFTP_ATTRS:
- 1566 $attrs = $this->_parseAttributes($response);
- 1567 return $attrs['permissions'];
- 1568 case NET_SFTP_STATUS:
- 1569 $this->_logError($response);
- 1570 return false;
- 1571 }
- 1572
- 1573 user_error('Expected SSH_FXP_ATTRS or SSH_FXP_STATUS');
- 1574 return false;
- 1575 }
- 1576
- 1577
- 1578
- 1579
- 1580
- 1581
- 1582
- 1583
- 1584
- 1585
- 1586 function _setstat($filename, $attr, $recursive)
- 1587 {
- 1588 if (!($this->bitmap & NET_SSH2_MASK_LOGIN)) {
- 1589 return false;
- 1590 }
- 1591
- 1592 $filename = $this->_realpath($filename);
- 1593 if ($filename === false) {
- 1594 return false;
- 1595 }
- 1596
- 1597 $this->_remove_from_stat_cache($filename);
- 1598
- 1599 if ($recursive) {
- 1600 $i = 0;
- 1601 $result = $this->_setstat_recursive($filename, $attr, $i);
- 1602 $this->_read_put_responses($i);
- 1603 return $result;
- 1604 }
- 1605
- 1606
- 1607
- 1608 if (!$this->_send_sftp_packet(NET_SFTP_SETSTAT, pack('Na*a*', strlen($filename), $filename, $attr))) {
- 1609 return false;
- 1610 }
- 1611
- 1612
- 1613
- 1614
- 1615
- 1616
- 1617
- 1618
- 1619 $response = $this->_get_sftp_packet();
- 1620 if ($this->packet_type != NET_SFTP_STATUS) {
- 1621 user_error('Expected SSH_FXP_STATUS');
- 1622 return false;
- 1623 }
- 1624
- 1625 if (strlen($response) < 4) {
- 1626 return false;
- 1627 }
- 1628 extract(unpack('Nstatus', $this->_string_shift($response, 4)));
- 1629 if ($status != NET_SFTP_STATUS_OK) {
- 1630 $this->_logError($response, $status);
- 1631 return false;
- 1632 }
- 1633
- 1634 return true;
- 1635 }
- 1636
- 1637
- 1638
- 1639
- 1640
- 1641
- 1642
- 1643
- 1644
- 1645
- 1646
- 1647
- 1648 function _setstat_recursive($path, $attr, &$i)
- 1649 {
- 1650 if (!$this->_read_put_responses($i)) {
- 1651 return false;
- 1652 }
- 1653 $i = 0;
- 1654 $entries = $this->_list($path, true);
- 1655
- 1656 if ($entries === false) {
- 1657 return $this->_setstat($path, $attr, false);
- 1658 }
- 1659
- 1660
- 1661
- 1662 if (empty($entries)) {
- 1663 return false;
- 1664 }
- 1665
- 1666 unset($entries['.'], $entries['..']);
- 1667 foreach ($entries as $filename => $props) {
- 1668 if (!isset($props['type'])) {
- 1669 return false;
- 1670 }
- 1671
- 1672 $temp = $path . '/' . $filename;
- 1673 if ($props['type'] == NET_SFTP_TYPE_DIRECTORY) {
- 1674 if (!$this->_setstat_recursive($temp, $attr, $i)) {
- 1675 return false;
- 1676 }
- 1677 } else {
- 1678 if (!$this->_send_sftp_packet(NET_SFTP_SETSTAT, pack('Na*a*', strlen($temp), $temp, $attr))) {
- 1679 return false;
- 1680 }
- 1681
- 1682 $i++;
- 1683
- 1684 if ($i >= NET_SFTP_QUEUE_SIZE) {
- 1685 if (!$this->_read_put_responses($i)) {
- 1686 return false;
- 1687 }
- 1688 $i = 0;
- 1689 }
- 1690 }
- 1691 }
- 1692
- 1693 if (!$this->_send_sftp_packet(NET_SFTP_SETSTAT, pack('Na*a*', strlen($path), $path, $attr))) {
- 1694 return false;
- 1695 }
- 1696
- 1697 $i++;
- 1698
- 1699 if ($i >= NET_SFTP_QUEUE_SIZE) {
- 1700 if (!$this->_read_put_responses($i)) {
- 1701 return false;
- 1702 }
- 1703 $i = 0;
- 1704 }
- 1705
- 1706 return true;
- 1707 }
- 1708
- 1709
- 1710
- 1711
- 1712
- 1713
- 1714
- 1715
- 1716 function readlink($link)
- 1717 {
- 1718 if (!($this->bitmap & NET_SSH2_MASK_LOGIN)) {
- 1719 return false;
- 1720 }
- 1721
- 1722 $link = $this->_realpath($link);
- 1723
- 1724 if (!$this->_send_sftp_packet(NET_SFTP_READLINK, pack('Na*', strlen($link), $link))) {
- 1725 return false;
- 1726 }
- 1727
- 1728 $response = $this->_get_sftp_packet();
- 1729 switch ($this->packet_type) {
- 1730 case NET_SFTP_NAME:
- 1731 break;
- 1732 case NET_SFTP_STATUS:
- 1733 $this->_logError($response);
- 1734 return false;
- 1735 default:
- 1736 user_error('Expected SSH_FXP_NAME or SSH_FXP_STATUS');
- 1737 return false;
- 1738 }
- 1739
- 1740 if (strlen($response) < 4) {
- 1741 return false;
- 1742 }
- 1743 extract(unpack('Ncount', $this->_string_shift($response, 4)));
- 1744
- 1745 if (!$count) {
- 1746 return false;
- 1747 }
- 1748
- 1749 if (strlen($response) < 4) {
- 1750 return false;
- 1751 }
- 1752 extract(unpack('Nlength', $this->_string_shift($response, 4)));
- 1753 return $this->_string_shift($response, $length);
- 1754 }
- 1755
- 1756
- 1757
- 1758
- 1759
- 1760
- 1761
- 1762
- 1763
- 1764
- 1765
- 1766 function symlink($target, $link)
- 1767 {
- 1768 if (!($this->bitmap & NET_SSH2_MASK_LOGIN)) {
- 1769 return false;
- 1770 }
- 1771
- 1772
- 1773 $link = $this->_realpath($link);
- 1774
- 1775 $packet = pack('Na*Na*', strlen($target), $target, strlen($link), $link);
- 1776 if (!$this->_send_sftp_packet(NET_SFTP_SYMLINK, $packet)) {
- 1777 return false;
- 1778 }
- 1779
- 1780 $response = $this->_get_sftp_packet();
- 1781 if ($this->packet_type != NET_SFTP_STATUS) {
- 1782 user_error('Expected SSH_FXP_STATUS');
- 1783 return false;
- 1784 }
- 1785
- 1786 if (strlen($response) < 4) {
- 1787 return false;
- 1788 }
- 1789 extract(unpack('Nstatus', $this->_string_shift($response, 4)));
- 1790 if ($status != NET_SFTP_STATUS_OK) {
- 1791 $this->_logError($response, $status);
- 1792 return false;
- 1793 }
- 1794
- 1795 return true;
- 1796 }
- 1797
- 1798
- 1799
- 1800
- 1801
- 1802
- 1803
- 1804
- 1805 function mkdir($dir, $mode = -1, $recursive = false)
- 1806 {
- 1807 if (!($this->bitmap & NET_SSH2_MASK_LOGIN)) {
- 1808 return false;
- 1809 }
- 1810
- 1811 $dir = $this->_realpath($dir);
- 1812
- 1813
- 1814 $attr = $mode == -1 ? "\0\0\0\0" : pack('N2', NET_SFTP_ATTR_PERMISSIONS, $mode & 07777);
- 1815
- 1816 if ($recursive) {
- 1817 $dirs = explode('/', preg_replace('#/(?=/)|/$#', '', $dir));
- 1818 if (empty($dirs[0])) {
- 1819 array_shift($dirs);
- 1820 $dirs[0] = '/' . $dirs[0];
- 1821 }
- 1822 for ($i = 0; $i < count($dirs); $i++) {
- 1823 $temp = array_slice($dirs, 0, $i + 1);
- 1824 $temp = implode('/', $temp);
- 1825 $result = $this->_mkdir_helper($temp, $attr);
- 1826 }
- 1827 return $result;
- 1828 }
- 1829
- 1830 return $this->_mkdir_helper($dir, $attr);
- 1831 }
- 1832
- 1833
- 1834
- 1835
- 1836
- 1837
- 1838
- 1839
- 1840 function _mkdir_helper($dir, $attr)
- 1841 {
- 1842 if (!$this->_send_sftp_packet(NET_SFTP_MKDIR, pack('Na*a*', strlen($dir), $dir, $attr))) {
- 1843 return false;
- 1844 }
- 1845
- 1846 $response = $this->_get_sftp_packet();
- 1847 if ($this->packet_type != NET_SFTP_STATUS) {
- 1848 user_error('Expected SSH_FXP_STATUS');
- 1849 return false;
- 1850 }
- 1851
- 1852 if (strlen($response) < 4) {
- 1853 return false;
- 1854 }
- 1855 extract(unpack('Nstatus', $this->_string_shift($response, 4)));
- 1856 if ($status != NET_SFTP_STATUS_OK) {
- 1857 $this->_logError($response, $status);
- 1858 return false;
- 1859 }
- 1860
- 1861 return true;
- 1862 }
- 1863
- 1864
- 1865
- 1866
- 1867
- 1868
- 1869
- 1870
- 1871 function rmdir($dir)
- 1872 {
- 1873 if (!($this->bitmap & NET_SSH2_MASK_LOGIN)) {
- 1874 return false;
- 1875 }
- 1876
- 1877 $dir = $this->_realpath($dir);
- 1878 if ($dir === false) {
- 1879 return false;
- 1880 }
- 1881
- 1882 if (!$this->_send_sftp_packet(NET_SFTP_RMDIR, pack('Na*', strlen($dir), $dir))) {
- 1883 return false;
- 1884 }
- 1885
- 1886 $response = $this->_get_sftp_packet();
- 1887 if ($this->packet_type != NET_SFTP_STATUS) {
- 1888 user_error('Expected SSH_FXP_STATUS');
- 1889 return false;
- 1890 }
- 1891
- 1892 if (strlen($response) < 4) {
- 1893 return false;
- 1894 }
- 1895 extract(unpack('Nstatus', $this->_string_shift($response, 4)));
- 1896 if ($status != NET_SFTP_STATUS_OK) {
- 1897
- 1898 $this->_logError($response, $status);
- 1899 return false;
- 1900 }
- 1901
- 1902 $this->_remove_from_stat_cache($dir);
- 1903
- 1904
- 1905
- 1906
- 1907
- 1908 return true;
- 1909 }
- 1910
- 1911
- 1912
- 1913
- 1914
- 1915
- 1916
- 1917
- 1918
- 1919
- 1920
- 1921
- 1922
- 1923
- 1924
- 1925
- 1926
- 1927
- 1928
- 1929
- 1930
- 1931
- 1932
- 1933
- 1934
- 1935
- 1936
- 1937
- 1938
- 1939
- 1940
- 1941
- 1942
- 1943
- 1944
- 1945
- 1946
- 1947
- 1948
- 1949
- 1950
- 1951
- 1952
- 1953
- 1954
- 1955
- 1956
- 1957
- 1958 function put($remote_file, $data, $mode = NET_SFTP_STRING, $start = -1, $local_start = -1, $progressCallback = null)
- 1959 {
- 1960 if (!($this->bitmap & NET_SSH2_MASK_LOGIN)) {
- 1961 return false;
- 1962 }
- 1963
- 1964 $remote_file = $this->_realpath($remote_file);
- 1965 if ($remote_file === false) {
- 1966 return false;
- 1967 }
- 1968
- 1969 $this->_remove_from_stat_cache($remote_file);
- 1970
- 1971 $flags = NET_SFTP_OPEN_WRITE | NET_SFTP_OPEN_CREATE;
- 1972
- 1973
- 1974
- 1975
- 1976 if ($start >= 0) {
- 1977 $offset = $start;
- 1978 } elseif ($mode & NET_SFTP_RESUME) {
- 1979
- 1980 $size = $this->size($remote_file);
- 1981 $offset = $size !== false ? $size : 0;
- 1982 } else {
- 1983 $offset = 0;
- 1984 $flags|= NET_SFTP_OPEN_TRUNCATE;
- 1985 }
- 1986
- 1987 $packet = pack('Na*N2', strlen($remote_file), $remote_file, $flags, 0);
- 1988 if (!$this->_send_sftp_packet(NET_SFTP_OPEN, $packet)) {
- 1989 return false;
- 1990 }
- 1991
- 1992 $response = $this->_get_sftp_packet();
- 1993 switch ($this->packet_type) {
- 1994 case NET_SFTP_HANDLE:
- 1995 $handle = substr($response, 4);
- 1996 break;
- 1997 case NET_SFTP_STATUS:
- 1998 $this->_logError($response);
- 1999 return false;
- 2000 default:
- 2001 user_error('Expected SSH_FXP_HANDLE or SSH_FXP_STATUS');
- 2002 return false;
- 2003 }
- 2004
- 2005
- 2006 $dataCallback = false;
- 2007 switch (true) {
- 2008 case $mode & NET_SFTP_CALLBACK:
- 2009 if (!is_callable($data)) {
- 2010 user_error("\$data should be is_callable if you set NET_SFTP_CALLBACK flag");
- 2011 }
- 2012 $dataCallback = $data;
- 2013
- 2014 break;
- 2015 case is_resource($data):
- 2016 $mode = $mode & ~NET_SFTP_LOCAL_FILE;
- 2017 $info = stream_get_meta_data($data);
- 2018 if ($info['wrapper_type'] == 'PHP' && $info['stream_type'] == 'Input') {
- 2019 $fp = fopen('php://memory', 'w+');
- 2020 stream_copy_to_stream($data, $fp);
- 2021 rewind($fp);
- 2022 } else {
- 2023 $fp = $data;
- 2024 }
- 2025 break;
- 2026 case $mode & NET_SFTP_LOCAL_FILE:
- 2027 if (!is_file($data)) {
- 2028 user_error("$data is not a valid file");
- 2029 return false;
- 2030 }
- 2031 $fp = @fopen($data, 'rb');
- 2032 if (!$fp) {
- 2033 return false;
- 2034 }
- 2035 }
- 2036
- 2037 if (isset($fp)) {
- 2038 $stat = fstat($fp);
- 2039 $size = !empty($stat) ? $stat['size'] : 0;
- 2040
- 2041 if ($local_start >= 0) {
- 2042 fseek($fp, $local_start);
- 2043 $size-= $local_start;
- 2044 }
- 2045 } elseif ($dataCallback) {
- 2046 $size = 0;
- 2047 } else {
- 2048 $size = strlen($data);
- 2049 }
- 2050
- 2051 $sent = 0;
- 2052 $size = $size < 0 ? ($size & 0x7FFFFFFF) + 0x80000000 : $size;
- 2053
- 2054 $sftp_packet_size = 4096;
- 2055
- 2056 $sftp_packet_size-= strlen($handle) + 25;
- 2057 $i = 0;
- 2058 while ($dataCallback || ($size === 0 || $sent < $size)) {
- 2059 if ($dataCallback) {
- 2060 $temp = call_user_func($dataCallback, $sftp_packet_size);
- 2061 if (is_null($temp)) {
- 2062 break;
- 2063 }
- 2064 } else {
- 2065 $temp = isset($fp) ? fread($fp, $sftp_packet_size) : substr($data, $sent, $sftp_packet_size);
- 2066 if ($temp === false || $temp === '') {
- 2067 break;
- 2068 }
- 2069 }
- 2070
- 2071 $subtemp = $offset + $sent;
- 2072 $packet = pack('Na*N3a*', strlen($handle), $handle, $subtemp / 4294967296, $subtemp, strlen($temp), $temp);
- 2073 if (!$this->_send_sftp_packet(NET_SFTP_WRITE, $packet)) {
- 2074 if ($mode & NET_SFTP_LOCAL_FILE) {
- 2075 fclose($fp);
- 2076 }
- 2077 return false;
- 2078 }
- 2079 $sent+= strlen($temp);
- 2080 if (is_callable($progressCallback)) {
- 2081 call_user_func($progressCallback, $sent);
- 2082 }
- 2083
- 2084 $i++;
- 2085
- 2086 if ($i == NET_SFTP_QUEUE_SIZE) {
- 2087 if (!$this->_read_put_responses($i)) {
- 2088 $i = 0;
- 2089 break;
- 2090 }
- 2091 $i = 0;
- 2092 }
- 2093 }
- 2094
- 2095 if (!$this->_read_put_responses($i)) {
- 2096 if ($mode & NET_SFTP_LOCAL_FILE) {
- 2097 fclose($fp);
- 2098 }
- 2099 $this->_close_handle($handle);
- 2100 return false;
- 2101 }
- 2102
- 2103 if ($mode & NET_SFTP_LOCAL_FILE) {
- 2104 fclose($fp);
- 2105 }
- 2106
- 2107 return $this->_close_handle($handle);
- 2108 }
- 2109
- 2110
- 2111
- 2112
- 2113
- 2114
- 2115
- 2116
- 2117
- 2118
- 2119
- 2120 function _read_put_responses($i)
- 2121 {
- 2122 while ($i--) {
- 2123 $response = $this->_get_sftp_packet();
- 2124 if ($this->packet_type != NET_SFTP_STATUS) {
- 2125 user_error('Expected SSH_FXP_STATUS');
- 2126 return false;
- 2127 }
- 2128
- 2129 if (strlen($response) < 4) {
- 2130 return false;
- 2131 }
- 2132 extract(unpack('Nstatus', $this->_string_shift($response, 4)));
- 2133 if ($status != NET_SFTP_STATUS_OK) {
- 2134 $this->_logError($response, $status);
- 2135 break;
- 2136 }
- 2137 }
- 2138
- 2139 return $i < 0;
- 2140 }
- 2141
- 2142
- 2143
- 2144
- 2145
- 2146
- 2147
- 2148
- 2149 function _close_handle($handle)
- 2150 {
- 2151 if (!$this->_send_sftp_packet(NET_SFTP_CLOSE, pack('Na*', strlen($handle), $handle))) {
- 2152 return false;
- 2153 }
- 2154
- 2155
- 2156
- 2157 $response = $this->_get_sftp_packet();
- 2158 if ($this->packet_type != NET_SFTP_STATUS) {
- 2159 user_error('Expected SSH_FXP_STATUS');
- 2160 return false;
- 2161 }
- 2162
- 2163 if (strlen($response) < 4) {
- 2164 return false;
- 2165 }
- 2166 extract(unpack('Nstatus', $this->_string_shift($response, 4)));
- 2167 if ($status != NET_SFTP_STATUS_OK) {
- 2168 $this->_logError($response, $status);
- 2169 return false;
- 2170 }
- 2171
- 2172 return true;
- 2173 }
- 2174
- 2175
- 2176
- 2177
- 2178
- 2179
- 2180
- 2181
- 2182
- 2183
- 2184
- 2185
- 2186
- 2187
- 2188
- 2189
- 2190
- 2191 function get($remote_file, $local_file = false, $offset = 0, $length = -1)
- 2192 {
- 2193 if (!($this->bitmap & NET_SSH2_MASK_LOGIN)) {
- 2194 return false;
- 2195 }
- 2196
- 2197 $remote_file = $this->_realpath($remote_file);
- 2198 if ($remote_file === false) {
- 2199 return false;
- 2200 }
- 2201
- 2202 $packet = pack('Na*N2', strlen($remote_file), $remote_file, NET_SFTP_OPEN_READ, 0);
- 2203 if (!$this->_send_sftp_packet(NET_SFTP_OPEN, $packet)) {
- 2204 return false;
- 2205 }
- 2206
- 2207 $response = $this->_get_sftp_packet();
- 2208 switch ($this->packet_type) {
- 2209 case NET_SFTP_HANDLE:
- 2210 $handle = substr($response, 4);
- 2211 break;
- 2212 case NET_SFTP_STATUS:
- 2213 $this->_logError($response);
- 2214 return false;
- 2215 default:
- 2216 user_error('Expected SSH_FXP_HANDLE or SSH_FXP_STATUS');
- 2217 return false;
- 2218 }
- 2219
- 2220 if (is_resource($local_file)) {
- 2221 $fp = $local_file;
- 2222 $stat = fstat($fp);
- 2223 $res_offset = $stat['size'];
- 2224 } else {
- 2225 $res_offset = 0;
- 2226 if ($local_file !== false) {
- 2227 $fp = fopen($local_file, 'wb');
- 2228 if (!$fp) {
- 2229 return false;
- 2230 }
- 2231 } else {
- 2232 $content = '';
- 2233 }
- 2234 }
- 2235
- 2236 $fclose_check = $local_file !== false && !is_resource($local_file);
- 2237
- 2238 $start = $offset;
- 2239 $read = 0;
- 2240 while (true) {
- 2241 $i = 0;
- 2242
- 2243 while ($i < NET_SFTP_QUEUE_SIZE && ($length < 0 || $read < $length)) {
- 2244 $tempoffset = $start + $read;
- 2245
- 2246 $packet_size = $length > 0 ? min($this->max_sftp_packet, $length - $read) : $this->max_sftp_packet;
- 2247
- 2248 $packet = pack('Na*N3', strlen($handle), $handle, $tempoffset / 4294967296, $tempoffset, $packet_size);
- 2249 if (!$this->_send_sftp_packet(NET_SFTP_READ, $packet)) {
- 2250 if ($fclose_check) {
- 2251 fclose($fp);
- 2252 }
- 2253 return false;
- 2254 }
- 2255 $packet = null;
- 2256 $read+= $packet_size;
- 2257 $i++;
- 2258 }
- 2259
- 2260 if (!$i) {
- 2261 break;
- 2262 }
- 2263
- 2264 $clear_responses = false;
- 2265 while ($i > 0) {
- 2266 $i--;
- 2267
- 2268 if ($clear_responses) {
- 2269 $this->_get_sftp_packet();
- 2270 continue;
- 2271 } else {
- 2272 $response = $this->_get_sftp_packet();
- 2273 }
- 2274
- 2275 switch ($this->packet_type) {
- 2276 case NET_SFTP_DATA:
- 2277 $temp = substr($response, 4);
- 2278 $offset+= strlen($temp);
- 2279 if ($local_file === false) {
- 2280 $content.= $temp;
- 2281 } else {
- 2282 fputs($fp, $temp);
- 2283 }
- 2284 $temp = null;
- 2285 break;
- 2286 case NET_SFTP_STATUS:
- 2287
- 2288 $this->_logError($response);
- 2289 $clear_responses = true;
- 2290 break;
- 2291 default:
- 2292 if ($fclose_check) {
- 2293 fclose($fp);
- 2294 }
- 2295 user_error('Expected SSH_FX_DATA or SSH_FXP_STATUS');
- 2296 }
- 2297 $response = null;
- 2298 }
- 2299
- 2300 if ($clear_responses) {
- 2301 break;
- 2302 }
- 2303 }
- 2304
- 2305 if ($length > 0 && $length <= $offset - $start) {
- 2306 if ($local_file === false) {
- 2307 $content = substr($content, 0, $length);
- 2308 } else {
- 2309 ftruncate($fp, $length + $res_offset);
- 2310 }
- 2311 }
- 2312
- 2313 if ($fclose_check) {
- 2314 fclose($fp);
- 2315 }
- 2316
- 2317 if (!$this->_close_handle($handle)) {
- 2318 return false;
- 2319 }
- 2320
- 2321
- 2322 return isset($content) ? $content : true;
- 2323 }
- 2324
- 2325
- 2326
- 2327
- 2328
- 2329
- 2330
- 2331
- 2332
- 2333 function delete($path, $recursive = true)
- 2334 {
- 2335 if (!($this->bitmap & NET_SSH2_MASK_LOGIN)) {
- 2336 return false;
- 2337 }
- 2338
- 2339 if (is_object($path)) {
- 2340
- 2341 $path = (string) $path;
- 2342 }
- 2343
- 2344 if (!is_string($path) || $path == '') {
- 2345 return false;
- 2346 }
- 2347
- 2348 $path = $this->_realpath($path);
- 2349 if ($path === false) {
- 2350 return false;
- 2351 }
- 2352
- 2353
- 2354 if (!$this->_send_sftp_packet(NET_SFTP_REMOVE, pack('Na*', strlen($path), $path))) {
- 2355 return false;
- 2356 }
- 2357
- 2358 $response = $this->_get_sftp_packet();
- 2359 if ($this->packet_type != NET_SFTP_STATUS) {
- 2360 user_error('Expected SSH_FXP_STATUS');
- 2361 return false;
- 2362 }
- 2363
- 2364
- 2365 if (strlen($response) < 4) {
- 2366 return false;
- 2367 }
- 2368 extract(unpack('Nstatus', $this->_string_shift($response, 4)));
- 2369 if ($status != NET_SFTP_STATUS_OK) {
- 2370 $this->_logError($response, $status);
- 2371 if (!$recursive) {
- 2372 return false;
- 2373 }
- 2374 $i = 0;
- 2375 $result = $this->_delete_recursive($path, $i);
- 2376 $this->_read_put_responses($i);
- 2377 return $result;
- 2378 }
- 2379
- 2380 $this->_remove_from_stat_cache($path);
- 2381
- 2382 return true;
- 2383 }
- 2384
- 2385
- 2386
- 2387
- 2388
- 2389
- 2390
- 2391
- 2392
- 2393
- 2394
- 2395 function _delete_recursive($path, &$i)
- 2396 {
- 2397 if (!$this->_read_put_responses($i)) {
- 2398 return false;
- 2399 }
- 2400 $i = 0;
- 2401 $entries = $this->_list($path, true);
- 2402
- 2403
- 2404
- 2405 if (empty($entries)) {
- 2406 return false;
- 2407 }
- 2408
- 2409 unset($entries['.'], $entries['..']);
- 2410 foreach ($entries as $filename => $props) {
- 2411 if (!isset($props['type'])) {
- 2412 return false;
- 2413 }
- 2414
- 2415 $temp = $path . '/' . $filename;
- 2416 if ($props['type'] == NET_SFTP_TYPE_DIRECTORY) {
- 2417 if (!$this->_delete_recursive($temp, $i)) {
- 2418 return false;
- 2419 }
- 2420 } else {
- 2421 if (!$this->_send_sftp_packet(NET_SFTP_REMOVE, pack('Na*', strlen($temp), $temp))) {
- 2422 return false;
- 2423 }
- 2424 $this->_remove_from_stat_cache($temp);
- 2425
- 2426 $i++;
- 2427
- 2428 if ($i >= NET_SFTP_QUEUE_SIZE) {
- 2429 if (!$this->_read_put_responses($i)) {
- 2430 return false;
- 2431 }
- 2432 $i = 0;
- 2433 }
- 2434 }
- 2435 }
- 2436
- 2437 if (!$this->_send_sftp_packet(NET_SFTP_RMDIR, pack('Na*', strlen($path), $path))) {
- 2438 return false;
- 2439 }
- 2440 $this->_remove_from_stat_cache($path);
- 2441
- 2442 $i++;
- 2443
- 2444 if ($i >= NET_SFTP_QUEUE_SIZE) {
- 2445 if (!$this->_read_put_responses($i)) {
- 2446 return false;
- 2447 }
- 2448 $i = 0;
- 2449 }
- 2450
- 2451 return true;
- 2452 }
- 2453
- 2454
- 2455
- 2456
- 2457
- 2458
- 2459
- 2460
- 2461 function file_exists($path)
- 2462 {
- 2463 if ($this->use_stat_cache) {
- 2464 $path = $this->_realpath($path);
- 2465
- 2466 $result = $this->_query_stat_cache($path);
- 2467
- 2468 if (isset($result)) {
- 2469
- 2470 return $result !== false;
- 2471 }
- 2472 }
- 2473
- 2474 return $this->stat($path) !== false;
- 2475 }
- 2476
- 2477
- 2478
- 2479
- 2480
- 2481
- 2482
- 2483
- 2484 function is_dir($path)
- 2485 {
- 2486 $result = $this->_get_stat_cache_prop($path, 'type');
- 2487 if ($result === false) {
- 2488 return false;
- 2489 }
- 2490 return $result === NET_SFTP_TYPE_DIRECTORY;
- 2491 }
- 2492
- 2493
- 2494
- 2495
- 2496
- 2497
- 2498
- 2499
- 2500 function is_file($path)
- 2501 {
- 2502 $result = $this->_get_stat_cache_prop($path, 'type');
- 2503 if ($result === false) {
- 2504 return false;
- 2505 }
- 2506 return $result === NET_SFTP_TYPE_REGULAR;
- 2507 }
- 2508
- 2509
- 2510
- 2511
- 2512
- 2513
- 2514
- 2515
- 2516 function is_link($path)
- 2517 {
- 2518 $result = $this->_get_lstat_cache_prop($path, 'type');
- 2519 if ($result === false) {
- 2520 return false;
- 2521 }
- 2522 return $result === NET_SFTP_TYPE_SYMLINK;
- 2523 }
- 2524
- 2525
- 2526
- 2527
- 2528
- 2529
- 2530
- 2531
- 2532 function is_readable($path)
- 2533 {
- 2534 $path = $this->_realpath($path);
- 2535
- 2536 $packet = pack('Na*N2', strlen($path), $path, NET_SFTP_OPEN_READ, 0);
- 2537 if (!$this->_send_sftp_packet(NET_SFTP_OPEN, $packet)) {
- 2538 return false;
- 2539 }
- 2540
- 2541 $response = $this->_get_sftp_packet();
- 2542 switch ($this->packet_type) {
- 2543 case NET_SFTP_HANDLE:
- 2544 return true;
- 2545 case NET_SFTP_STATUS:
- 2546 return false;
- 2547 default:
- 2548 user_error('Expected SSH_FXP_HANDLE or SSH_FXP_STATUS');
- 2549 return false;
- 2550 }
- 2551 }
- 2552
- 2553
- 2554
- 2555
- 2556
- 2557
- 2558
- 2559
- 2560 function is_writable($path)
- 2561 {
- 2562 $path = $this->_realpath($path);
- 2563
- 2564 $packet = pack('Na*N2', strlen($path), $path, NET_SFTP_OPEN_WRITE, 0);
- 2565 if (!$this->_send_sftp_packet(NET_SFTP_OPEN, $packet)) {
- 2566 return false;
- 2567 }
- 2568
- 2569 $response = $this->_get_sftp_packet();
- 2570 switch ($this->packet_type) {
- 2571 case NET_SFTP_HANDLE:
- 2572 return true;
- 2573 case NET_SFTP_STATUS:
- 2574 return false;
- 2575 default:
- 2576 user_error('Expected SSH_FXP_HANDLE or SSH_FXP_STATUS');
- 2577 return false;
- 2578 }
- 2579 }
- 2580
- 2581
- 2582
- 2583
- 2584
- 2585
- 2586
- 2587
- 2588
- 2589
- 2590 function is_writeable($path)
- 2591 {
- 2592 return $this->is_writable($path);
- 2593 }
- 2594
- 2595
- 2596
- 2597
- 2598
- 2599
- 2600
- 2601
- 2602 function fileatime($path)
- 2603 {
- 2604 return $this->_get_stat_cache_prop($path, 'atime');
- 2605 }
- 2606
- 2607
- 2608
- 2609
- 2610
- 2611
- 2612
- 2613
- 2614 function filemtime($path)
- 2615 {
- 2616 return $this->_get_stat_cache_prop($path, 'mtime');
- 2617 }
- 2618
- 2619
- 2620
- 2621
- 2622
- 2623
- 2624
- 2625
- 2626 function fileperms($path)
- 2627 {
- 2628 return $this->_get_stat_cache_prop($path, 'permissions');
- 2629 }
- 2630
- 2631
- 2632
- 2633
- 2634
- 2635
- 2636
- 2637
- 2638 function fileowner($path)
- 2639 {
- 2640 return $this->_get_stat_cache_prop($path, 'uid');
- 2641 }
- 2642
- 2643
- 2644
- 2645
- 2646
- 2647
- 2648
- 2649
- 2650 function filegroup($path)
- 2651 {
- 2652 return $this->_get_stat_cache_prop($path, 'gid');
- 2653 }
- 2654
- 2655
- 2656
- 2657
- 2658
- 2659
- 2660
- 2661
- 2662 function filesize($path)
- 2663 {
- 2664 return $this->_get_stat_cache_prop($path, 'size');
- 2665 }
- 2666
- 2667
- 2668
- 2669
- 2670
- 2671
- 2672
- 2673
- 2674 function filetype($path)
- 2675 {
- 2676 $type = $this->_get_stat_cache_prop($path, 'type');
- 2677 if ($type === false) {
- 2678 return false;
- 2679 }
- 2680
- 2681 switch ($type) {
- 2682 case NET_SFTP_TYPE_BLOCK_DEVICE:
- 2683 return 'block';
- 2684 case NET_SFTP_TYPE_CHAR_DEVICE:
- 2685 return 'char';
- 2686 case NET_SFTP_TYPE_DIRECTORY:
- 2687 return 'dir';
- 2688 case NET_SFTP_TYPE_FIFO:
- 2689 return 'fifo';
- 2690 case NET_SFTP_TYPE_REGULAR:
- 2691 return 'file';
- 2692 case NET_SFTP_TYPE_SYMLINK:
- 2693 return 'link';
- 2694 default:
- 2695 return false;
- 2696 }
- 2697 }
- 2698
- 2699
- 2700
- 2701
- 2702
- 2703
- 2704
- 2705
- 2706
- 2707
- 2708
- 2709 function _get_stat_cache_prop($path, $prop)
- 2710 {
- 2711 return $this->_get_xstat_cache_prop($path, $prop, 'stat');
- 2712 }
- 2713
- 2714
- 2715
- 2716
- 2717
- 2718
- 2719
- 2720
- 2721
- 2722
- 2723
- 2724 function _get_lstat_cache_prop($path, $prop)
- 2725 {
- 2726 return $this->_get_xstat_cache_prop($path, $prop, 'lstat');
- 2727 }
- 2728
- 2729
- 2730
- 2731
- 2732
- 2733
- 2734
- 2735
- 2736
- 2737
- 2738
- 2739 function _get_xstat_cache_prop($path, $prop, $type)
- 2740 {
- 2741 if ($this->use_stat_cache) {
- 2742 $path = $this->_realpath($path);
- 2743
- 2744 $result = $this->_query_stat_cache($path);
- 2745
- 2746 if (is_object($result) && isset($result->$type)) {
- 2747 return $result->{$type}[$prop];
- 2748 }
- 2749 }
- 2750
- 2751 $result = $this->$type($path);
- 2752
- 2753 if ($result === false || !isset($result[$prop])) {
- 2754 return false;
- 2755 }
- 2756
- 2757 return $result[$prop];
- 2758 }
- 2759
- 2760
- 2761
- 2762
- 2763
- 2764
- 2765
- 2766
- 2767
- 2768 function rename($oldname, $newname)
- 2769 {
- 2770 if (!($this->bitmap & NET_SSH2_MASK_LOGIN)) {
- 2771 return false;
- 2772 }
- 2773
- 2774 $oldname = $this->_realpath($oldname);
- 2775 $newname = $this->_realpath($newname);
- 2776 if ($oldname === false || $newname === false) {
- 2777 return false;
- 2778 }
- 2779
- 2780
- 2781 $packet = pack('Na*Na*', strlen($oldname), $oldname, strlen($newname), $newname);
- 2782 if (!$this->_send_sftp_packet(NET_SFTP_RENAME, $packet)) {
- 2783 return false;
- 2784 }
- 2785
- 2786 $response = $this->_get_sftp_packet();
- 2787 if ($this->packet_type != NET_SFTP_STATUS) {
- 2788 user_error('Expected SSH_FXP_STATUS');
- 2789 return false;
- 2790 }
- 2791
- 2792
- 2793 if (strlen($response) < 4) {
- 2794 return false;
- 2795 }
- 2796 extract(unpack('Nstatus', $this->_string_shift($response, 4)));
- 2797 if ($status != NET_SFTP_STATUS_OK) {
- 2798 $this->_logError($response, $status);
- 2799 return false;
- 2800 }
- 2801
- 2802
- 2803
- 2804
- 2805 $this->_remove_from_stat_cache($oldname);
- 2806 $this->_remove_from_stat_cache($newname);
- 2807
- 2808 return true;
- 2809 }
- 2810
- 2811
- 2812
- 2813
- 2814
- 2815
- 2816
- 2817
- 2818
- 2819
- 2820 function _parseAttributes(&$response)
- 2821 {
- 2822 $attr = array();
- 2823 if (strlen($response) < 4) {
- 2824 user_error('Malformed file attributes');
- 2825 return array();
- 2826 }
- 2827 extract(unpack('Nflags', $this->_string_shift($response, 4)));
- 2828
- 2829 foreach ($this->attributes as $key => $value) {
- 2830 switch ($flags & $key) {
- 2831 case NET_SFTP_ATTR_SIZE:
- 2832
- 2833
- 2834
- 2835
- 2836
- 2837
- 2838 $attr['size'] = hexdec(bin2hex($this->_string_shift($response, 8)));
- 2839 break;
- 2840 case NET_SFTP_ATTR_UIDGID:
- 2841 if (strlen($response) < 8) {
- 2842 user_error('Malformed file attributes');
- 2843 return $attr;
- 2844 }
- 2845 $attr+= unpack('Nuid/Ngid', $this->_string_shift($response, 8));
- 2846 break;
- 2847 case NET_SFTP_ATTR_PERMISSIONS:
- 2848 if (strlen($response) < 4) {
- 2849 user_error('Malformed file attributes');
- 2850 return $attr;
- 2851 }
- 2852 $attr+= unpack('Npermissions', $this->_string_shift($response, 4));
- 2853
- 2854
- 2855 $attr+= array('mode' => $attr['permissions']);
- 2856 $fileType = $this->_parseMode($attr['permissions']);
- 2857 if ($fileType !== false) {
- 2858 $attr+= array('type' => $fileType);
- 2859 }
- 2860 break;
- 2861 case NET_SFTP_ATTR_ACCESSTIME:
- 2862 if (strlen($response) < 8) {
- 2863 user_error('Malformed file attributes');
- 2864 return $attr;
- 2865 }
- 2866 $attr+= unpack('Natime/Nmtime', $this->_string_shift($response, 8));
- 2867 break;
- 2868 case NET_SFTP_ATTR_EXTENDED:
- 2869 if (strlen($response) < 4) {
- 2870 user_error('Malformed file attributes');
- 2871 return $attr;
- 2872 }
- 2873 extract(unpack('Ncount', $this->_string_shift($response, 4)));
- 2874 for ($i = 0; $i < $count; $i++) {
- 2875 if (strlen($response) < 4) {
- 2876 user_error('Malformed file attributes');
- 2877 return $attr;
- 2878 }
- 2879 extract(unpack('Nlength', $this->_string_shift($response, 4)));
- 2880 $key = $this->_string_shift($response, $length);
- 2881 if (strlen($response) < 4) {
- 2882 user_error('Malformed file attributes');
- 2883 return $attr;
- 2884 }
- 2885 extract(unpack('Nlength', $this->_string_shift($response, 4)));
- 2886 $attr[$key] = $this->_string_shift($response, $length);
- 2887 }
- 2888 }
- 2889 }
- 2890 return $attr;
- 2891 }
- 2892
- 2893
- 2894
- 2895
- 2896
- 2897
- 2898
- 2899
- 2900
- 2901
- 2902 function _parseMode($mode)
- 2903 {
- 2904
- 2905
- 2906 switch ($mode & 0170000) {
- 2907 case 0000000:
- 2908 return false;
- 2909 case 0040000:
- 2910 return NET_SFTP_TYPE_DIRECTORY;
- 2911 case 0100000:
- 2912 return NET_SFTP_TYPE_REGULAR;
- 2913 case 0120000:
- 2914 return NET_SFTP_TYPE_SYMLINK;
- 2915
- 2916
- 2917 case 0010000:
- 2918 return NET_SFTP_TYPE_FIFO;
- 2919 case 0020000:
- 2920 return NET_SFTP_TYPE_CHAR_DEVICE;
- 2921 case 0060000:
- 2922 return NET_SFTP_TYPE_BLOCK_DEVICE;
- 2923 case 0140000:
- 2924 return NET_SFTP_TYPE_SOCKET;
- 2925 case 0160000:
- 2926
- 2927
- 2928 return NET_SFTP_TYPE_SPECIAL;
- 2929 default:
- 2930 return NET_SFTP_TYPE_UNKNOWN;
- 2931 }
- 2932 }
- 2933
- 2934
- 2935
- 2936
- 2937
- 2938
- 2939
- 2940
- 2941
- 2942
- 2943
- 2944
- 2945
- 2946
- 2947
- 2948
- 2949 function _parseLongname($longname)
- 2950 {
- 2951
- 2952
- 2953 if (preg_match('#^[^/]([r-][w-][xstST-]){3}#', $longname)) {
- 2954 switch ($longname[0]) {
- 2955 case '-':
- 2956 return NET_SFTP_TYPE_REGULAR;
- 2957 case 'd':
- 2958 return NET_SFTP_TYPE_DIRECTORY;
- 2959 case 'l':
- 2960 return NET_SFTP_TYPE_SYMLINK;
- 2961 default:
- 2962 return NET_SFTP_TYPE_SPECIAL;
- 2963 }
- 2964 }
- 2965
- 2966 return false;
- 2967 }
- 2968
- 2969
- 2970
- 2971
- 2972
- 2973
- 2974
- 2975
- 2976
- 2977
- 2978
- 2979
- 2980
- 2981 function _send_sftp_packet($type, $data)
- 2982 {
- 2983 $packet = $this->request_id !== false ?
- 2984 pack('NCNa*', strlen($data) + 5, $type, $this->request_id, $data) :
- 2985 pack('NCa*', strlen($data) + 1, $type, $data);
- 2986
- 2987 $start = strtok(microtime(), ' ') + strtok('');
- 2988 $result = $this->_send_channel_packet(NET_SFTP_CHANNEL, $packet);
- 2989 $stop = strtok(microtime(), ' ') + strtok('');
- 2990
- 2991 if (defined('NET_SFTP_LOGGING')) {
- 2992 $packet_type = '-> ' . $this->packet_types[$type] .
- 2993 ' (' . round($stop - $start, 4) . 's)';
- 2994 if (NET_SFTP_LOGGING == NET_SFTP_LOG_REALTIME) {
- 2995 echo "<pre>\r\n" . $this->_format_log(array($data), array($packet_type)) . "\r\n</pre>\r\n";
- 2996 flush();
- 2997 ob_flush();
- 2998 } else {
- 2999 $this->packet_type_log[] = $packet_type;
- 3000 if (NET_SFTP_LOGGING == NET_SFTP_LOG_COMPLEX) {
- 3001 $this->packet_log[] = $data;
- 3002 }
- 3003 }
- 3004 }
- 3005
- 3006 return $result;
- 3007 }
- 3008
- 3009
- 3010
- 3011
- 3012
- 3013
- 3014
- 3015
- 3016
- 3017
- 3018
- 3019
- 3020
- 3021
- 3022 function _get_sftp_packet()
- 3023 {
- 3024 $this->curTimeout = false;
- 3025
- 3026 $start = strtok(microtime(), ' ') + strtok('');
- 3027
- 3028
- 3029 while (strlen($this->packet_buffer) < 4) {
- 3030 $temp = $this->_get_channel_packet(NET_SFTP_CHANNEL, true);
- 3031 if (is_bool($temp)) {
- 3032 $this->packet_type = false;
- 3033 $this->packet_buffer = '';
- 3034 return false;
- 3035 }
- 3036 $this->packet_buffer.= $temp;
- 3037 }
- 3038 if (strlen($this->packet_buffer) < 4) {
- 3039 return false;
- 3040 }
- 3041 extract(unpack('Nlength', $this->_string_shift($this->packet_buffer, 4)));
- 3042 $tempLength = $length;
- 3043 $tempLength-= strlen($this->packet_buffer);
- 3044
- 3045
- 3046 while ($tempLength > 0) {
- 3047 $temp = $this->_get_channel_packet(NET_SFTP_CHANNEL, true);
- 3048 if (is_bool($temp)) {
- 3049 $this->packet_type = false;
- 3050 $this->packet_buffer = '';
- 3051 return false;
- 3052 }
- 3053 $this->packet_buffer.= $temp;
- 3054 $tempLength-= strlen($temp);
- 3055 }
- 3056
- 3057 $stop = strtok(microtime(), ' ') + strtok('');
- 3058
- 3059 $this->packet_type = ord($this->_string_shift($this->packet_buffer));
- 3060
- 3061 if ($this->request_id !== false) {
- 3062 $this->_string_shift($this->packet_buffer, 4);
- 3063 $length-= 5;
- 3064 } else {
- 3065 $length-= 1;
- 3066 }
- 3067
- 3068 $packet = $this->_string_shift($this->packet_buffer, $length);
- 3069
- 3070 if (defined('NET_SFTP_LOGGING')) {
- 3071 $packet_type = '<- ' . $this->packet_types[$this->packet_type] .
- 3072 ' (' . round($stop - $start, 4) . 's)';
- 3073 if (NET_SFTP_LOGGING == NET_SFTP_LOG_REALTIME) {
- 3074 echo "<pre>\r\n" . $this->_format_log(array($packet), array($packet_type)) . "\r\n</pre>\r\n";
- 3075 flush();
- 3076 ob_flush();
- 3077 } else {
- 3078 $this->packet_type_log[] = $packet_type;
- 3079 if (NET_SFTP_LOGGING == NET_SFTP_LOG_COMPLEX) {
- 3080 $this->packet_log[] = $packet;
- 3081 }
- 3082 }
- 3083 }
- 3084
- 3085 return $packet;
- 3086 }
- 3087
- 3088
- 3089
- 3090
- 3091
- 3092
- 3093
- 3094
- 3095
- 3096 function getSFTPLog()
- 3097 {
- 3098 if (!defined('NET_SFTP_LOGGING')) {
- 3099 return false;
- 3100 }
- 3101
- 3102 switch (NET_SFTP_LOGGING) {
- 3103 case NET_SFTP_LOG_COMPLEX:
- 3104 return $this->_format_log($this->packet_log, $this->packet_type_log);
- 3105 break;
- 3106
- 3107 default:
- 3108 return $this->packet_type_log;
- 3109 }
- 3110 }
- 3111
- 3112
- 3113
- 3114
- 3115
- 3116
- 3117
- 3118 function getSFTPErrors()
- 3119 {
- 3120 return $this->sftp_errors;
- 3121 }
- 3122
- 3123
- 3124
- 3125
- 3126
- 3127
- 3128
- 3129 function getLastSFTPError()
- 3130 {
- 3131 return count($this->sftp_errors) ? $this->sftp_errors[count($this->sftp_errors) - 1] : '';
- 3132 }
- 3133
- 3134
- 3135
- 3136
- 3137
- 3138
- 3139
- 3140 function getSupportedVersions()
- 3141 {
- 3142 $temp = array('version' => $this->version);
- 3143 if (isset($this->extensions['versions'])) {
- 3144 $temp['extensions'] = $this->extensions['versions'];
- 3145 }
- 3146 return $temp;
- 3147 }
- 3148
- 3149
- 3150
- 3151
- 3152
- 3153
- 3154
- 3155
- 3156 function _disconnect($reason)
- 3157 {
- 3158 $this->pwd = false;
- 3159 parent::_disconnect($reason);
- 3160 }
- 3161 }